#include "MCGraphicsItem.h"
#include <MCSettings.h>
#include <cmath>
#include <MCUtils.h>
#include <MCMathUtils.h>
#include <MCArc2D.h>
#include <iostream>

MCGraphicsItem::MCGraphicsItem(ICanvas *presenter_) :
    presenter(presenter_),
    _painter(nullptr),
    _isSelected(false)
{
    initParams();
}

void MCGraphicsItem::setColor(const MCColor &color)
{
    _defaultColor = color;
    _pen.setColor(MCUtils::toQColor(color));
}

void MCGraphicsItem::setFillColor(const MCColor &color)
{
    _defaultFillColor = color;
}

void MCGraphicsItem::setThickness(double thickness)
{
    _thickness = abs(thickness);
    _pen.setWidth(_thickness);
}

void MCGraphicsItem::setLayerIndex(int layerIndex)
{
    _layerIndex = layerIndex;
}

bool MCGraphicsItem::isVisible()
{
    return _visibility == ItemVisibility::Visible;
}

void MCGraphicsItem::select()
{
    _isSelected = true;
    setHighlight(ItemHighlight::Selected);
}

void MCGraphicsItem::deselect()
{
    _isSelected = false;
    setHighlight(ItemHighlight::NoHightlight);
}

bool MCGraphicsItem::isSelected()
{
    return _isSelected;
}

void MCGraphicsItem::hoverEnter()
{
    setHighlight(ItemHighlight::Hovered);
}

void MCGraphicsItem::hoverLeave()
{
    setHighlight(ItemHighlight::NoHightlight);
}

void MCGraphicsItem::setHighlight(ItemHighlight highlight)
{
    if (highlight == ItemHighlight::NoHightlight)
    {
        _pen.setColor(MCUtils::toQColor(_defaultColor));
    }
    else if (highlight == ItemHighlight::Selected)
    {
        _pen.setColor(MCUtils::toQColor(_selectedColor));
    }
    else if (highlight == ItemHighlight::Hovered)
    {
        _pen.setColor(MCUtils::toQColor(_hoveredColor));
    }
}

void MCGraphicsItem::setVisible(ItemVisibility visibility)
{
    if (visibility == ItemVisibility::Visible)
    {
        _pen.setColor(MCUtils::toQColor(_defaultFillColor));
    }
    else if (visibility == ItemVisibility::Invisible)
    {
        _pen.setColor(MCUtils::toQColor(MCColors::Transparent));
    }

    _visibility = visibility;
}

ICanvas *MCGraphicsItem::canvas()
{
    return presenter;
}

std::vector<IGripPoint *> MCGraphicsItem::grips()
{
    //resetGrips();
    return gripPoints;
}

void MCGraphicsItem::setGripAt(IGripPoint *grip, const MCPoint2D &pos)
{
}

void MCGraphicsItem::resetGrips()
{
}

void MCGraphicsItem::setPainter(QPainter *painter)
{
    _painter = painter;
    _painter->setBrush(MCUtils::toQColor(_defaultFillColor));
    _pen.setWidth(_thickness);
    _painter->setPen(_pen);
}

void MCGraphicsItem::initParams()
{
    _defaultColor = MCSettings::DefaultColor;
    _defaultFillColor = MCSettings::DefaultFillColor;
    _hoveredColor = MCSettings::HoveredColor;
    _selectedColor = MCSettings::SelectedColor;
    _thickness = MCSettings::defaultThickness;
    _layerIndex = MCSettings::defaultLayer;
    _visibility = ItemVisibility::Visible;
}

void MCGraphicsItem::drawLineSegment(const MCPoint2D &p1, const MCPoint2D &p2)
{
    if (_painter != nullptr)
    {
        QPoint qp1(p1.x, p1.y);
        QPoint qp2(p2.x, p2.y);

        _painter->drawLine(qp1, qp2);
    }
}

void MCGraphicsItem::drawRect(const MCPoint2D &topLeft, const MCPoint2D &bottomRight)
{
    if (_painter != nullptr)
    {
        QPointF tp(topLeft.x, topLeft.y);
        QPointF br(bottomRight.x, bottomRight.y);

        _painter->drawRect(QRectF(tp, br));
    }
}

void MCGraphicsItem::drawCircle(const MCPoint2D &center, double radius)
{
    if (_painter != nullptr)
    {
        QPoint qcenter(center.x, center.y);
        int r = radius;

        _painter->drawEllipse(qcenter, r, r);
    }
}

void MCGraphicsItem::drawEllipse(const MCPoint2D & center, double rx, double ry)
{
    if (_painter != nullptr)
    {
        QPoint qcenter(center.x, center.y);
        int qrx = rx;
        int qry = ry;

        _painter->drawEllipse(qcenter, qrx, qry);
    }
}

void MCGraphicsItem::drawPoint(const MCPoint2D &point)
{
    if (_painter != nullptr)
    {
        QPoint qp(point.x, point.y);
        int width = MCSettings::GripPointWidth / 3;

        _painter->drawEllipse(qp, width, width);
    }
}

void MCGraphicsItem::drawArc(const MCPoint2D &center, double radius, double sAngle, double eAngle)
{
    MCArc2D arc(center, radius, sAngle, eAngle);
    double startAngle = MCMathUtils::radianToDegree(arc.startAngle()) * 16;
    double endAngle = MCMathUtils::radianToDegree(arc.endAngle()) * 16;

    if (endAngle < startAngle)
    {
        endAngle = 360 * 16 + endAngle;
    }

    double spanAngle = std::abs(endAngle) - std::abs(startAngle);

    QPoint lt(arc.center().x - arc.radius(), arc.center().y + arc.radius());
    QPoint rb(arc.center().x + arc.radius(), arc.center().y - arc.radius());

    _painter->drawArc(QRect(lt, rb), startAngle, spanAngle);
}

void MCGraphicsItem::drawArrow2(const MCPoint2D & p1, const MCPoint2D & p2, double length, double sharpness, double scale)
{
    if (_painter != nullptr)
    {
        MCPoint2D d = p2 - p1;
        double ostr = 0.25;
        double lons = length;
        double angle = std::atan2(d.y, d.x);
        double f1x2 = p2.x - lons * std::cos(angle - ostr);
        double f1y2 = p2.y - lons * std::sin(angle - ostr);
        drawLineSegment(p1, p2);

        drawLineSegment(MCPoint2D(p2.x, p2.y), MCPoint2D(f1x2, f1y2));

        f1x2 = p2.x - lons * std::cos(angle + ostr);
        f1y2 = p2.y - lons * std::sin(angle + ostr);

        drawLineSegment(MCPoint2D(p2.x, p2.y), MCPoint2D(f1x2, f1y2));
    }
}

void MCGraphicsItem::drawArrow(QPainter *painter, QPoint start, QPoint end, qreal arrowSize_)
{
    qreal arrowSize = arrowSize_ / presenter->scale();
    QLineF line(end, start);

    double angle = std::atan2(-line.dy(), line.dx());
    QPointF arrowP1 = line.p1() + QPointF(sin(angle + M_PI / 3) * arrowSize,
        cos(angle + M_PI / 3) * arrowSize);
    QPointF arrowP2 = line.p1() + QPointF(sin(angle + M_PI - M_PI / 3) * arrowSize,
        cos(angle + M_PI - M_PI / 3) * arrowSize);

    QPolygonF arrowHead;
    arrowHead.clear();
    arrowHead << line.p1() << arrowP1 << arrowP2;
    painter->drawLine(line);
    painter->drawPolygon(arrowHead);
}

void MCGraphicsItem::drawVector(const MCPoint2D &start, const MCVector2 &dir)
{
    MCPoint2D p1 = start;
    MCPoint2D p2 = start + dir;
    drawArrow2(p1, p2, 30, 1);
}

void MCGraphicsItem::drawLabel(const MCPoint2D &topLeft, double width, double height, const std::string &pathToImage)
{
    if (_painter != nullptr)
    {
        QRectF rect(topLeft.x, topLeft.y, width, height);
        _painter->drawRect(rect);
        _painter->drawImage(rect, QImage(QString::fromStdString(pathToImage)));
    }
}

void MCGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{

}

QRectF MCGraphicsItem::boundingRect() const
{
    return QRectF();
}

QPainterPath MCGraphicsItem::shape() const
{
    return QPainterPath();
}
